package com.ybg.engine.task;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;

import org.apache.commons.lang3.StringUtils;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.StatefulJob;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.JdbcUtils;

import com.ybg.engine.TaskResult;
import com.ybg.engine.mail.StatiMailWrapper;
import com.ybg.util.DataSourceUtil;
import com.ybg.util.LogUtil;
import com.ybg.util.SysParamUtil;

/**
 * 任务抽象父类，定义了子类的实现流程，和捕捉异常，保存调度结果
 * @author zhouqixin
 *
 */
@SuppressWarnings("deprecation")
public abstract class Task implements StatefulJob {
	protected JdbcTemplate jdbcTemplate;
	
	/**
	 * 调度的流程函数
	 */
    public void execute(JobExecutionContext context) throws JobExecutionException {
    	DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    	jdbcTemplate  = DataSourceUtil.beanFactory.getBean("jdbcTemplate", JdbcTemplate.class);
    	
    	TaskResult taskResult=new TaskResult();
        taskResult.setClassname(this.getClass().getName());
        taskResult.setStarttime(df.format(new Date()));
        taskResult.setStatus(TaskResult.RUN_SUCCESS);
        
        try{
        	// 执行具体任务
        	run();
        	
        	// 获取任务执行结果
        	taskResult.setMsg(setSuccessResultMsg());
        }catch(Exception ex){
        	// 异常信息
        	StringBuilder errorMsg = new StringBuilder();
        	for(int h = 0; h< ex.getStackTrace().length; h++){
        		errorMsg.append(ex.getStackTrace()[h] + "\n");
			}
        	
        	// 设置失败信息
        	taskResult.setStatus(TaskResult.RUN_FAIL);
        	taskResult.setMsg(errorMsg.toString());
        	
        	// 发送错误信息邮件
        	StatiMailWrapper mailSender = new StatiMailWrapper();
			mailSender.setSubject("调度引擎运行错误 - " + SysParamUtil.getSimpleConfigValue("schoolName"));
			mailSender.addMsg("调度任务名称：", taskResult.getClassname());
			mailSender.addMsg("异常发生时间 ：", df.format(new Date()));
			mailSender.addMsg("异常信息", errorMsg.toString());
			mailSender.sendMail(jdbcTemplate);
        }
        
        taskResult.setEndtime(df.format(new Date()));
        jdbcTemplate.update("insert into task_log(xlh,classname,starttime,endtime,status,msg) "
        		+ "values(?,?,?,?,?,?)", UUID.randomUUID().toString(),taskResult.getClassname(),
        		taskResult.getStarttime(),taskResult.getEndtime(),taskResult.getStatus(),
        		taskResult.getMsg());
    }
    
    /**
     * 调度任务运行的主体
     */
	public abstract void run() throws Exception;
	/**
	 * 设置运行成功的返回信息
	 * @return
	 */
	public abstract String setSuccessResultMsg();
	
	/**
     * 保存对象到数据库
     * 
     * @param t 对象实例
     * @return
     * @throws Exception
     */
    protected <T> boolean save(T t) throws Exception {
    	StringBuilder sql   = new StringBuilder("insert into ");
    	StringBuilder val   = new StringBuilder("values(");
    	Class<?>      clazz = t.getClass();
    	
    	// 获得实体类的Table注解，用来确定数据库表
    	Table table = clazz.getAnnotation(Table.class);
    	
    	if(table == null) {
    		LogUtil.warn("必须在实体类定义Table注解！");
    		return false;
    	} else {
    		sql.append(table.name()).append("(");
    	}
    	
    	List<Object> values = new ArrayList<Object>();
    	Field[]      fields = t.getClass().getDeclaredFields();
    	
    	// 装拼需要保存的字段(有Column注解的字段才保存)
    	// 暂不对主键做处理，用户需要保证主键ID大于0
    	for(int i = 0; i < fields.length; i++) {
    		Column column = fields[i].getAnnotation(Column.class);
    		
    		if(column != null) {
    			sql.append(column.name());
    			val.append("?");
    			
    			values.add(clazz.getMethod("get" + StringUtils.capitalize(fields[i].getName())).invoke(t));
    			
    			if(i < (fields.length - 1)) {
    				sql.append(", ");
    				val.append(", ");
    			}
    		}
    	}
    	
    	if(values.size() == 0) {
    		LogUtil.warn("没有数据需要更新到表！");
    		return false;
    	}
    	
    	sql.append(") ").append(val.append(")"));
    	
    	return jdbcTemplate.update(sql.toString(), values.toArray()) == 1;
    }
    
    /**
     * 根据主键更新对象到数据库
     * 
     * @param t 对象实例
     * @return
     * @throws Exception
     */
    protected <T> boolean update(T t) throws Exception {
    	StringBuilder sql   = new StringBuilder("update ");
    	Class<?>      clazz = t.getClass();
    	
    	// 获得实体类的Table注解，用来确定数据库表
    	Table table = clazz.getAnnotation(Table.class);
    	
    	if(table == null) {
    		LogUtil.warn("必须在实体类定义Table注解！");
    		return false;
    	} else {
    		sql.append(table.name()).append(" set ");
    	}
    	
    	List<Object> values = new ArrayList<Object>();
    	Field[]      fields = t.getClass().getDeclaredFields();
    	Field       idField = null;
    	
    	// 装拼需要保存的字段(有Column注解的字段才保存)
    	for(int i = 0; i < fields.length; i++) {
    		Id id = fields[i].getAnnotation(Id.class);
    		
    		if(id != null) {
    			idField = fields[i];
    			continue;
    		}
    		
    		Column column = fields[i].getAnnotation(Column.class);
    		
    		if(column != null) {
    			sql.append(column.name()).append(" = ?");
    			values.add(clazz.getMethod("get" + StringUtils.capitalize(fields[i].getName())).invoke(t));
    			
    			if(i < (fields.length - 1)) {
    				sql.append(", ");
    			}
    		}
    	}
    	
    	if(values.size() == 0) {
    		LogUtil.warn("没有数据需要更新到表！");
    		return false;
    	}
    	
    	// 若不存在主键则报错
    	if(idField == null) {
    		LogUtil.warn("缺少主键，无法定位更新的行！");
    		return false;
    	} else {
    		Column column = idField.getAnnotation(Column.class);
    		
    		if(column == null) {
    			LogUtil.warn("缺少主键，无法定位更新的行！");
        		return false;
    		} else {
    			sql.append(" where ").append(column.name()).append(" = ?");
    			values.add(clazz.getMethod("get" + StringUtils.capitalize(idField.getName())).invoke(t));
    		}
    	}
    	
    	return jdbcTemplate.update(sql.toString(), values.toArray()) == 1;
    }
    
    /**
     * 根据主键删除对象记录
     * 
     * @param t 对象实例
     * @return
     * @throws Exception
     */
    protected <T> boolean delete(T t) throws Exception {
    	StringBuilder sql   = new StringBuilder("delete from ");
    	Class<?>      clazz = t.getClass();
    	
    	// 获得实体类的Table注解，用来确定数据库表
    	Table table = clazz.getAnnotation(Table.class);
    	
    	if(table == null) {
    		LogUtil.warn("必须在实体类定义Table注解！");
    		return false;
    	} else {
    		sql.append(table.name());
    	}
    	
    	Field[] fields = t.getClass().getDeclaredFields();
    	Field  idField = null;
    	Object idValue = null;
    	
    	for(Field field : fields) {
    		Id id = field.getAnnotation(Id.class);
    		
    		if(id != null) {
    			idField = field;
    			break;
    		}
    	}
    	
    	// 若不存在主键则报错
    	if(idField == null) {
    		LogUtil.warn("缺少主键，无法定位更新的行！");
    		return false;
    	} else {
    		Column column = idField.getAnnotation(Column.class);
    		
    		if(column == null) {
    			LogUtil.warn("缺少主键，无法定位更新的行！");
        		return false;
    		} else {
    			sql.append(" where ").append(column.name()).append(" = ?");
    			idValue = clazz.getMethod("get" + StringUtils.capitalize(idField.getName())).invoke(t);
    		}
    	}
    	
    	return jdbcTemplate.update(sql.toString(), idValue) == 1;
    }
    
    /**
     * 批量保存对象到数据库
     * @param list		对象列表
     * @param clazz		泛型对象类型
     * @return
     */
	public <T> int[] batchSave(final List<T> list, final Class<T> clazz) {
		StringBuilder sql = new StringBuilder("insert into ");
		StringBuilder val = new StringBuilder("values(");
    	
    	// 获得实体类的Table注解，用来确定数据库表
    	Table table = clazz.getAnnotation(Table.class);
    	
    	if(table == null) {
    		LogUtil.warn("必须在实体类定义Table注解！");
    		return null;
    	} else {
    		sql.append(table.name()).append("(");
    	}
    	
		final Field[] fields = clazz.getDeclaredFields();
    	
    	// 装拼需要保存的字段(有Column注解的字段才保存)
    	// 暂不对主键做处理，用户需要保证主键ID大于0
    	for(int i = 0; i < fields.length; i++) {
    		Column column = fields[i].getAnnotation(Column.class);
    		
    		if(column != null) {
    			sql.append(column.name());
    			val.append("?");
    			
    			if(i < (fields.length - 1)) {
    				sql.append(", ");
    				val.append(", ");
    			}
    		}
    	}
    	
    	sql.append(") ").append(val.append(")"));
		
		return jdbcTemplate.batchUpdate(sql.toString(), new BatchPreparedStatementSetter() {
			@Override
			public void setValues(PreparedStatement ps, int i) throws SQLException {
				int parameterIndex = 1;
				Object fieldValueObj = null;
				for(Field field : fields) {
					Column column = field.getAnnotation(Column.class);

					if(column != null) {
						String methodName = "get" + StringUtils.capitalize(field.getName());
						Class<?> fieldType  = field.getType();
						Method getMethod  = null;

						try {
							getMethod = clazz.getMethod(methodName);
							fieldValueObj = getMethod.invoke(list.get(i));
							
							if (fieldValueObj != null) {
								if(fieldType == String.class) {
									ps.setString(parameterIndex++, (String) fieldValueObj);
								} else if(fieldType == long.class || fieldType == Long.class) {
									ps.setLong(parameterIndex++, (long) fieldValueObj);
								} else if(fieldType == int.class || fieldType == Integer.class) {
									ps.setInt(parameterIndex++, (int) fieldValueObj);
								} else if(fieldType == Date.class) {
									ps.setTimestamp(parameterIndex++, new Timestamp(((Date) fieldValueObj).getTime()));
								} else if(fieldType == double.class || fieldType == Double.class) {
									ps.setDouble(parameterIndex++, (double) fieldValueObj);
								} else if(fieldType == float.class || fieldType == Float.class) {
									ps.setFloat(parameterIndex++, (float) fieldValueObj);
								} else if(fieldType == byte.class || fieldType == Byte.class || fieldType == char.class) {
									ps.setByte(parameterIndex++, (byte) fieldValueObj);
								} else if(fieldType == short.class || fieldType == Short.class) {
									ps.setShort(parameterIndex++, (short) fieldValueObj);
								} else {
									ps.setObject(parameterIndex++, fieldValueObj);
								}
							} else {
								if(fieldType == String.class) {
									ps.setNull(parameterIndex++, Types.VARCHAR);
								} else if(fieldType == long.class || fieldType == Long.class) {
									ps.setNull(parameterIndex++, Types.BIGINT);
								} else if(fieldType == int.class || fieldType == Integer.class) {
									ps.setNull(parameterIndex++, Types.INTEGER);
								} else if(fieldType == Date.class) {
									// ps.setNull(parameterIndex++, Types.DATE);
									ps.setNull(parameterIndex++, Types.TIMESTAMP);
								} else if(fieldType == double.class || fieldType == Double.class) {
									ps.setNull(parameterIndex++, Types.DOUBLE);
								} else if(fieldType == float.class || fieldType == Float.class) {
									ps.setNull(parameterIndex++, Types.FLOAT);
								} else if(fieldType == byte.class || fieldType == Byte.class || fieldType == char.class) {
									ps.setNull(parameterIndex++, Types.BINARY);
								} else if(fieldType == short.class || fieldType == Short.class) {
									ps.setNull(parameterIndex++, Types.TINYINT);
								} else {
									ps.setObject(parameterIndex++, null);
								}
							}
						} catch(Exception e) {
							e.printStackTrace();
							LogUtil.error("转化实体类错误: " + e.getMessage());
						}
					}
				}
			}

			@Override
			public int getBatchSize() {
				return list.size();
			}
		});
	}
	
	/**
     * 批量更新对象到数据库
     * @param list		对象列表
     * @param clazz		泛型对象类型
     * @return
     */
	public <T> int[] batchUpdate(final List<T> list, final Class<T> clazz) {
		StringBuilder sql = new StringBuilder("update ");
    	
    	// 获得实体类的Table注解，用来确定数据库表
    	Table table = clazz.getAnnotation(Table.class);
    	
    	if(table == null) {
    		LogUtil.warn("必须在实体类定义Table注解！");
    		return null;
    	} else {
    		sql.append(table.name()).append(" set ");
    	}
    	
		final Field[] fields = clazz.getDeclaredFields();
		Field idField = null;
    	
    	// 装拼需要保存的字段(有Column注解的字段才保存)
    	for(int i = 0; i < fields.length; i++) {
    		Id id = fields[i].getAnnotation(Id.class);
    		
    		if(id != null) {
    			idField = fields[i];
    			continue;
    		}
    		
    		Column column = fields[i].getAnnotation(Column.class);
    		
    		if(column != null) {
    			sql.append(column.name()).append(" = ?");
    			
    			if(i < (fields.length - 1)) {
    				sql.append(", ");
    			}
    		}
    	}
    	
    	// 若不存在主键则报错
    	if(idField == null) {
    		LogUtil.warn("缺少主键，无法定位更新的行！");
    		return null;
    	} else {
    		Column idColumn = idField.getAnnotation(Column.class);
    		
    		if(idColumn == null) {
    			LogUtil.warn("缺少主键，无法定位更新的行！");
        		return null;
    		} else {
    			sql.append(" where ").append(idColumn.name()).append(" = ?");
    		}
    	}
		
		return jdbcTemplate.batchUpdate(sql.toString(), new BatchPreparedStatementSetter() {
			@Override
			public void setValues(PreparedStatement ps, int i) throws SQLException {
				Id id = null;
				Field idField = null;
				
				int parameterIndex = 1;
				Object fieldValueObj = null;
				for(Field field : fields) {
					id = field.getAnnotation(Id.class);
		    		
		    		if(id != null) {
		    			idField = field;
		    			continue;
		    		}
		    		
					Column column = field.getAnnotation(Column.class);

					if(column != null) {
						String methodName = "get" + StringUtils.capitalize(field.getName());
						Class<?> fieldType  = field.getType();
						Method getMethod  = null;

						try {
							getMethod = clazz.getMethod(methodName);
							fieldValueObj = getMethod.invoke(list.get(i));
							
							if (fieldValueObj != null) {
								if(fieldType == String.class) {
									ps.setString(parameterIndex++, (String) fieldValueObj);
								} else if(fieldType == long.class || fieldType == Long.class) {
									ps.setLong(parameterIndex++, (long) fieldValueObj);
								} else if(fieldType == int.class || fieldType == Integer.class) {
									ps.setInt(parameterIndex++, (int) fieldValueObj);
								} else if(fieldType == Date.class) {
									ps.setTimestamp(parameterIndex++, new Timestamp(((Date) fieldValueObj).getTime()));
								} else if(fieldType == double.class || fieldType == Double.class) {
									ps.setDouble(parameterIndex++, (double) fieldValueObj);
								} else if(fieldType == float.class || fieldType == Float.class) {
									ps.setFloat(parameterIndex++, (float) fieldValueObj);
								} else if(fieldType == byte.class || fieldType == Byte.class || fieldType == char.class) {
									ps.setByte(parameterIndex++, (byte) fieldValueObj);
								} else if(fieldType == short.class || fieldType == Short.class) {
									ps.setShort(parameterIndex++, (short) fieldValueObj);
								} else {
									ps.setObject(parameterIndex++, fieldValueObj);
								}
							} else {
								if(fieldType == String.class) {
									ps.setNull(parameterIndex++, Types.VARCHAR);
								} else if(fieldType == long.class || fieldType == Long.class) {
									ps.setNull(parameterIndex++, Types.BIGINT);
								} else if(fieldType == int.class || fieldType == Integer.class) {
									ps.setNull(parameterIndex++, Types.INTEGER);
								} else if(fieldType == Date.class) {
									// ps.setNull(parameterIndex++, Types.DATE);
									ps.setNull(parameterIndex++, Types.TIMESTAMP);
								} else if(fieldType == double.class || fieldType == Double.class) {
									ps.setNull(parameterIndex++, Types.DOUBLE);
								} else if(fieldType == float.class || fieldType == Float.class) {
									ps.setNull(parameterIndex++, Types.FLOAT);
								} else if(fieldType == byte.class || fieldType == Byte.class || fieldType == char.class) {
									ps.setNull(parameterIndex++, Types.BINARY);
								} else if(fieldType == short.class || fieldType == Short.class) {
									ps.setNull(parameterIndex++, Types.TINYINT);
								} else {
									ps.setObject(parameterIndex++, null);
								}
							}
						} catch(Exception e) {
							LogUtil.error("转化实体类错误: " + e.getMessage());
						}
					}
				}
				
				Column idColumn = idField.getAnnotation(Column.class);
				
				if(idColumn != null) {
					String methodName = "get" + StringUtils.capitalize(idField.getName());
					Class<?> fieldType  = idField.getType();
					Method getMethod  = null;

					try {
						getMethod = clazz.getMethod(methodName);
						fieldValueObj = getMethod.invoke(list.get(i));
						
						if (fieldValueObj != null) {
							if(fieldType == String.class) {
								ps.setString(parameterIndex++, (String) fieldValueObj);
							} else if(fieldType == long.class || fieldType == Long.class) {
								ps.setLong(parameterIndex++, (long) fieldValueObj);
							} else if(fieldType == int.class || fieldType == Integer.class) {
								ps.setInt(parameterIndex++, (int) fieldValueObj);
							} else if(fieldType == Date.class) {
								ps.setTimestamp(parameterIndex++, new Timestamp(((Date) fieldValueObj).getTime()));
							} else if(fieldType == double.class || fieldType == Double.class) {
								ps.setDouble(parameterIndex++, (double) fieldValueObj);
							} else if(fieldType == float.class || fieldType == Float.class) {
								ps.setFloat(parameterIndex++, (float) fieldValueObj);
							} else if(fieldType == byte.class || fieldType == Byte.class || fieldType == char.class) {
								ps.setByte(parameterIndex++, (byte) fieldValueObj);
							} else if(fieldType == short.class || fieldType == Short.class) {
								ps.setShort(parameterIndex++, (short) fieldValueObj);
							} else {
								ps.setObject(parameterIndex++, fieldValueObj);
							}
						} else {
							if(fieldType == String.class) {
								ps.setNull(parameterIndex++, Types.VARCHAR);
							} else if(fieldType == long.class || fieldType == Long.class) {
								ps.setNull(parameterIndex++, Types.BIGINT);
							} else if(fieldType == int.class || fieldType == Integer.class) {
								ps.setNull(parameterIndex++, Types.INTEGER);
							} else if(fieldType == Date.class) {
								// ps.setNull(parameterIndex++, Types.DATE);
								ps.setNull(parameterIndex++, Types.TIMESTAMP);
							} else if(fieldType == double.class || fieldType == Double.class) {
								ps.setNull(parameterIndex++, Types.DOUBLE);
							} else if(fieldType == float.class || fieldType == Float.class) {
								ps.setNull(parameterIndex++, Types.FLOAT);
							} else if(fieldType == byte.class || fieldType == Byte.class || fieldType == char.class) {
								ps.setNull(parameterIndex++, Types.BINARY);
							} else if(fieldType == short.class || fieldType == Short.class) {
								ps.setNull(parameterIndex++, Types.TINYINT);
							} else {
								ps.setObject(parameterIndex++, null);
							}
						}
					} catch(Exception e) {
						LogUtil.error("转化实体类错误: " + e.getMessage());
					}
				}
			}

			@Override
			public int getBatchSize() {
				return list.size();
			}
		});
	}
	
	/**
     * 批量更新对象到数据库（可选仅更新个别字段）
     * @param list					对象列表
     * @param clazz					泛型对象类型
     * @param selectiveFieldNames	要更新的字段的名称
     * @param idFieldName			主键字段的名称
     * @return
     */
	public <T> int[] batchOptionalUpdate(final List<T> list, final Class<T> clazz, final List<String> selectiveFieldNames, final String idFieldName) {
		StringBuilder sql = new StringBuilder("update ");
    	
    	// 获得实体类的Table注解，用来确定数据库表
    	Table table = clazz.getAnnotation(Table.class);
    	
    	if(table == null) {
    		LogUtil.warn("必须在实体类定义Table注解！");
    		return null;
    	} else {
    		sql.append(table.name()).append(" set ");
    	}
    	
		int len = selectiveFieldNames.size();
		
		if (len < 1) {
			LogUtil.warn("无需更新的字段！");
			return null;
		}
    	// 装拼需要保存的字段
    	for(int i = 0; i < len; i++) {
    		if(StringUtils.isNotEmpty(selectiveFieldNames.get(i))) {
    			sql.append(selectiveFieldNames.get(i)).append(" = ?");
    			
    			if(i < (len - 1)) {
    				sql.append(", ");
    			}
    		}
    	}
    	
    	// 若不存在主键则报错
    	if(StringUtils.isNotEmpty(idFieldName)) {
    		LogUtil.warn("缺少主键，无法定位更新的行！");
    		return null;
    	} else {
    		sql.append(" where ").append(idFieldName).append(" = ?");
    	}
    	
		return jdbcTemplate.batchUpdate(sql.toString(), new BatchPreparedStatementSetter() {
			@Override
			public void setValues(PreparedStatement ps, int i) throws SQLException {
				Field[] fields = clazz.getDeclaredFields();
				
				int parameterIndex = 1;
				Object fieldValueObj = null;
				for(String selectiveFieldName : selectiveFieldNames) {
					if(StringUtils.isNotEmpty(selectiveFieldName)) {
						String methodName = "get" + StringUtils.capitalize(selectiveFieldName);
						Class<?> fieldType  = null;
						for (Field field : fields) {
							if (field.getName().equals(selectiveFieldName)) {
								fieldType = field.getType();
								break;
							}
						}
						Method getMethod  = null;

						try {
							getMethod = clazz.getMethod(methodName);
							fieldValueObj = getMethod.invoke(list.get(i));
							
							if (fieldValueObj != null) {
								if(fieldType == String.class) {
									ps.setString(parameterIndex++, (String) fieldValueObj);
								} else if(fieldType == long.class || fieldType == Long.class) {
									ps.setLong(parameterIndex++, (long) fieldValueObj);
								} else if(fieldType == int.class || fieldType == Integer.class) {
									ps.setInt(parameterIndex++, (int) fieldValueObj);
								} else if(fieldType == Date.class) {
									ps.setTimestamp(parameterIndex++, new Timestamp(((Date) fieldValueObj).getTime()));
								} else if(fieldType == double.class || fieldType == Double.class) {
									ps.setDouble(parameterIndex++, (double) fieldValueObj);
								} else if(fieldType == float.class || fieldType == Float.class) {
									ps.setFloat(parameterIndex++, (float) fieldValueObj);
								} else if(fieldType == byte.class || fieldType == Byte.class || fieldType == char.class) {
									ps.setByte(parameterIndex++, (byte) fieldValueObj);
								} else if(fieldType == short.class || fieldType == Short.class) {
									ps.setShort(parameterIndex++, (short) fieldValueObj);
								} else {
									ps.setObject(parameterIndex++, fieldValueObj);
								}
							} else {
								if(fieldType == String.class) {
									ps.setNull(parameterIndex++, Types.VARCHAR);
								} else if(fieldType == long.class || fieldType == Long.class) {
									ps.setNull(parameterIndex++, Types.BIGINT);
								} else if(fieldType == int.class || fieldType == Integer.class) {
									ps.setNull(parameterIndex++, Types.INTEGER);
								} else if(fieldType == Date.class) {
									// ps.setNull(parameterIndex++, Types.DATE);
									ps.setNull(parameterIndex++, Types.TIMESTAMP);
								} else if(fieldType == double.class || fieldType == Double.class) {
									ps.setNull(parameterIndex++, Types.DOUBLE);
								} else if(fieldType == float.class || fieldType == Float.class) {
									ps.setNull(parameterIndex++, Types.FLOAT);
								} else if(fieldType == byte.class || fieldType == Byte.class || fieldType == char.class) {
									ps.setNull(parameterIndex++, Types.BINARY);
								} else if(fieldType == short.class || fieldType == Short.class) {
									ps.setNull(parameterIndex++, Types.TINYINT);
								} else {
									ps.setObject(parameterIndex++, null);
								}
							}
						} catch(Exception e) {
							LogUtil.error("转化实体类错误: " + e.getMessage());
						}
					}
				}
				
				if(StringUtils.isNotEmpty(idFieldName)) {
					String methodName = "get" + StringUtils.capitalize(idFieldName);
					Class<?> fieldType  = null;
					for (Field field : fields) {
						if (field.getName().equals(idFieldName)) {
							fieldType = field.getType();
							break;
						}
					}
					Method getMethod  = null;

					try {
						getMethod = clazz.getMethod(methodName);
						fieldValueObj = getMethod.invoke(list.get(i));
						
						if (fieldValueObj != null) {
							if(fieldType == String.class) {
								ps.setString(parameterIndex++, (String) fieldValueObj);
							} else if(fieldType == long.class || fieldType == Long.class) {
								ps.setLong(parameterIndex++, (long) fieldValueObj);
							} else if(fieldType == int.class || fieldType == Integer.class) {
								ps.setInt(parameterIndex++, (int) fieldValueObj);
							} else if(fieldType == Date.class) {
								ps.setTimestamp(parameterIndex++, new Timestamp(((Date) fieldValueObj).getTime()));
							} else if(fieldType == double.class || fieldType == Double.class) {
								ps.setDouble(parameterIndex++, (double) fieldValueObj);
							} else if(fieldType == float.class || fieldType == Float.class) {
								ps.setFloat(parameterIndex++, (float) fieldValueObj);
							} else if(fieldType == byte.class || fieldType == Byte.class || fieldType == char.class) {
								ps.setByte(parameterIndex++, (byte) fieldValueObj);
							} else if(fieldType == short.class || fieldType == Short.class) {
								ps.setShort(parameterIndex++, (short) fieldValueObj);
							} else {
								ps.setObject(parameterIndex++, fieldValueObj);
							}
						} else {
							if(fieldType == String.class) {
								ps.setNull(parameterIndex++, Types.VARCHAR);
							} else if(fieldType == long.class || fieldType == Long.class) {
								ps.setNull(parameterIndex++, Types.BIGINT);
							} else if(fieldType == int.class || fieldType == Integer.class) {
								ps.setNull(parameterIndex++, Types.INTEGER);
							} else if(fieldType == Date.class) {
								// ps.setNull(parameterIndex++, Types.DATE);
								ps.setNull(parameterIndex++, Types.TIMESTAMP);
							} else if(fieldType == double.class || fieldType == Double.class) {
								ps.setNull(parameterIndex++, Types.DOUBLE);
							} else if(fieldType == float.class || fieldType == Float.class) {
								ps.setNull(parameterIndex++, Types.FLOAT);
							} else if(fieldType == byte.class || fieldType == Byte.class || fieldType == char.class) {
								ps.setNull(parameterIndex++, Types.BINARY);
							} else if(fieldType == short.class || fieldType == Short.class) {
								ps.setNull(parameterIndex++, Types.TINYINT);
							} else {
								ps.setObject(parameterIndex++, null);
							}
						}
					} catch(Exception e) {
						LogUtil.error("转化实体类错误: " + e.getMessage());
					}
				}
			}

			@Override
			public int getBatchSize() {
				return list.size();
			}
		});
	}
	
	/**
     * 用于JDBCTemplate查询结果转成小写Key的Map&lt;String, Object&gt;
     */
    protected static class LowerCaseMapRowMapper implements RowMapper<Map<String, Object>> {
    	public LowerCaseMapRowMapper() {
    		
    	}
    	
    	private Map<String, Object> newInstance(int columnCount) {
    		return new LinkedHashMap<>(columnCount);
    	}
    	
		@Override
		public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
			ResultSetMetaData rsMetaData = rs.getMetaData();
			int columnCount = rsMetaData.getColumnCount();

			Map<String, Object> map = newInstance(columnCount);
			for (int i = 1; i <= columnCount; i++) {
				String key = rsMetaData.getColumnName(i);
				Object valueObj = JdbcUtils.getResultSetValue(rs, i);
				map.put(key.toLowerCase(), valueObj);
			}
			return map;
		}
    }

	/**
	 * 用于JDBCTemplate查询结果转成实体类
	 */
	protected static class YbgRowMapper<T> implements RowMapper<T> {
		private Class<T> clazz;

		public YbgRowMapper(Class<T> clazz) {
			this.clazz = clazz;
		}

		private T newInstance() {
			T t = null;

			try {
				t = clazz.newInstance();
			} catch (Exception e) {
				LogUtil.error("所用实体类不能转化:"+e.getMessage());
			}

			return t;
		}

		private String getSetMethodName(String name) {
			return "set" + StringUtils.capitalize(name);
		}

		@Override
		public T mapRow(ResultSet rs, int rowNum) throws SQLException {
			T t = newInstance();

			Field[] fields = clazz.getDeclaredFields();
			for(Field field : fields) {
				Column column = field.getAnnotation(Column.class);

				if(column != null) {
					String   methodName = getSetMethodName(field.getName());
					Class<?> fieldType  = field.getType();
					Method setMethod  = null;
					Object   parameter  = null;

					try {
						setMethod = clazz.getMethod(methodName, fieldType);

						if(fieldType == String.class) {
							parameter = rs.getString(column.name());
						} else if(fieldType == long.class || fieldType == Long.class) {
							parameter = rs.getLong(column.name());
						} else if(fieldType == int.class || fieldType == Integer.class) {
							parameter = rs.getInt(column.name());
						} else if(fieldType == Date.class) {
							Timestamp timestamp = rs.getTimestamp(column.name());
							if(timestamp != null) {
								parameter = new Date(timestamp.getTime());
							}
						} else if(fieldType == double.class || fieldType == Double.class) {
							parameter = rs.getDouble(column.name());
						} else if(fieldType == float.class || fieldType == Float.class) {
							parameter = rs.getFloat(column.name());
						} else if(fieldType == byte.class || fieldType == Byte.class || fieldType == char.class) {
							parameter = rs.getByte(column.name());
						} else if(fieldType == short.class || fieldType == Short.class) {
							parameter = rs.getShort(column.name());
						}

						if(parameter != null) setMethod.invoke(t, parameter);
					} catch(Exception e) {
						LogUtil.error("转化实体类错误:"+e.getMessage());
					}
				}
			}

			return t;
		}
	}
}
